;================================================================
;  magnify.s
;               The Magnifying effect
;
;================================================================
;
; 25thanni, a demo dedicated to the 25th anniversary of the ZX81.
;
; (c)2006 Bodo Wenzel
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License as
; published by the Free Software Foundation; either version 2 of
; the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public
; License along with this program; if not, write to the Free
; Software Foundation Inc., 59 Temple Place, Suite 330, Boston,
; MA 02111-1307 USA
;================================================================

	.module	magnify

;= Externals ====================================================

	.globl	heap_ptr
	.globl	hrg_file

	.globl	check_break
	.globl	set_show
	.globl	show_dummy
	.globl	vsync
	.globl	b_check

	.globl	G0,G1,G2,G3,G4,G5,G6,G7,G8,G9,GA,GB,GC,GD,GE,GF
	.globl	__,X8,X9,XA,QU,PD,DL,CL,QM,LP,RP,GT,LT,EQ,PL,MI
	.globl	TI,SL,SC,CM,PE,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9
	.globl	_A,_B,_C,_D,_E,_F,_G,_H,_I,_J,_K,_L,_M,_N,_O,_P
	.globl	_Q,_R,_S,_T,_U,_V,_W,_X,_Y,_Z,NL,INV

	.globl	HRG_WIDTH,HRG_HEIGHT
	.globl	show_hrg
	.globl	h_out_up
	.globl	h_in_down
	.globl	h_check

	.globl	MATH_SIGN,MATH_TWO_PI
	.globl	sine

	.globl	unpack

;= Constants ====================================================

; double global definition checked by linker
HRG_WIDTH	==	256
HRG_HEIGHT	==	192
MATH_TWO_PI	==	256

BITS_PER_BYTE	=	8
BYTES_PER_WORD	=	2

BITS_PER_PIXEL	=	2
PIC_WIDTH	=	128
PIC_HEIGHT	=	24
BYTE_WIDTH	=	PIC_WIDTH/BITS_PER_BYTE
PIC_SIZE	=	BITS_PER_PIXEL*PIC_HEIGHT*BYTE_WIDTH

BG_WIDTH	=	512
REPETITIONS	=	BG_WIDTH/PIC_WIDTH
SHIFT		=	3

NUMBER_OF_BARS	=	3
BAR_OFFSET	=	(HRG_HEIGHT-MATH_TWO_PI/2)/2
BAR_WIDTH	=	19

;= Program code =================================================

	.area	CODE

;- Show the Magnifying effect -----------------------------------

magnify::
	ld	hl,#show_dummy
	call	set_show

	ld	hl,(heap_ptr)
	ld	de,#PIC_SIZE*REPETITIONS
	add	hl,de
	push	hl
	ld	de,#picture
	ld	bc,#PAC_PIC_SIZE
	call	unpack
	pop	hl

	ld	de,(heap_ptr)
	ld	a,#BITS_PER_PIXEL*PIC_HEIGHT
	and	a		; clear C flag
m_pic_olp:
	ld	bc,#BYTE_WIDTH
	ldir
	ld	b,#REPETITIONS-1
m_pic_ilp:
	push	bc
	ld	bc,#BYTE_WIDTH
	sbc	hl,bc
	ldir
	pop	bc
	djnz	m_pic_ilp
	dec	a
	jr	nz,m_pic_olp	; create the pixel buffer

	ld	hl,#white_line
	ld	b,#HRG_WIDTH/BITS_PER_BYTE
m_white_lp:
	ld	(hl),#0
	inc	hl
	djnz	m_white_lp

	ld	hl,#black_line
	ld	b,#HRG_WIDTH/BITS_PER_BYTE
m_black_lp:
	ld	(hl),#~0
	inc	hl
	djnz	m_black_lp

	ex	de,hl
	ld	(hrg_file_1),hl
	ld	de,(heap_ptr)
	call	prepare		; pointer table for picture 1

	ld	(hrg_file_2),hl
	ex	de,hl
	ld	hl,(heap_ptr)
	ld	bc,#PIC_HEIGHT*BG_WIDTH/BITS_PER_BYTE
	add	hl,bc
	ex	de,hl
	call	prepare		; pointer table for picture 2

	ld	(hrg_file),hl
	ex	de,hl
	ld	hl,(hrg_file_1)
	ld	bc,#HRG_HEIGHT*BYTES_PER_WORD
	ldir			; initialize hrg_file

	ex	de,hl
	ld	(show_hrg),hl
	ld	de,#scroll_line
	ld	bc,#PAC_SL_SIZE
	call	unpack

	call	h_in_down

	ld	hl,#show_hrg
	call	set_show

	ld	hl,#bar_offsets
	ld	b,#NUMBER_OF_BARS
	ld	a,#MATH_TWO_PI/NUMBER_OF_BARS/2
m_bar_lp:
	ld	(hl),a
	inc	hl
	add	a,#MATH_TWO_PI/NUMBER_OF_BARS
	djnz	m_bar_lp

	scf
	push	af
m_loop:
	ld	hl,(hrg_file_1)
	xor	a
	call	patch

	ld	hl,(hrg_file_2)
	ld	a,#1
	call	patch

	call	check_break
	jr	nc,m_quit

	pop	af
	push	af
	call	c,b_check
	jr	nz,m_loop	; bottom scroller not finished?

m_quit:
	pop	af
	call	c,h_out_up
	xor	a
	push	af

	call	h_check
	jr	nz,m_loop	; roll out not finished?

	pop	af
	ret

;- Prepare table of pointers ------------------------------------
; DE	pointer to bitmap
; HL	pointer to table to prepare

prepare:
	ld	c,#HRG_HEIGHT/PIC_HEIGHT
p_olp:
	ld	b,#PIC_HEIGHT
	push	de
p_ilp:
	ld	(hl),e
	inc	hl
	ld	(hl),d
	inc	hl

	ld	a,e
	add	a,#BG_WIDTH/BITS_PER_BYTE
	ld	e,a
	jr	nc,p_inx
	inc	d
p_inx:
	djnz	p_ilp		; pointers of the bitmap

	pop	de
	ld	a,e
	add	a,#SHIFT
	ld	e,a
	jr	nc,p_onx
	inc	d		; shift a bit for repetitions
p_onx:
	dec	c
	jr	nz,p_olp

	ret

;- Apply the magnifying effect by shifting pointers -------------
; A	change of bar offsets
; HL	pointer to saved pointer table
; destination line	source line
;		-9	white
;		-8	-6
;		-7	-4
;		-6	-4
;		-5	-2
;		-4	-2
;		-3	-1
;		-2	-1
;		-1	0
;		0	0
;		+1	0
;		+2	+1
;		+3	+1
;		+4	+2
;		+5	+2
;		+6	+4
;		+7	+4
;		+8	+6
;		+9	black

patch:
	push	af
	push	hl
	call	vsync
	pop	hl
	pop	af

	ld	de,(hrg_file)
	ld	bc,#HRG_HEIGHT*BYTES_PER_WORD
	ldir			; restore pointer table

	ld	hl,#bar_offsets
	ld	c,a
	ld	b,#NUMBER_OF_BARS
p_bar_loop:
	ld	a,(hl)
	add	a,c
	ld	(hl),a
	inc	hl
	exx

	ld	hl,(hrg_file)
	ld	de,#BAR_OFFSET*BYTES_PER_WORD+1
	add	hl,de
	call	sine
	xor	#MATH_SIGN
	and	#-BYTES_PER_WORD
	ld	e,a
	ld	d,#0
	add	hl,de		; calculate pointer to center

	ld	b,(hl)
	dec	hl
	ld	c,(hl)		; get line 0
	dec	hl
	ld	d,(hl)
	ld	(hl),b
	dec	hl
	ld	e,(hl)
	ld	(hl),c		; get line -1, set line 0
	dec	hl
	ld	b,(hl)
	ld	(hl),d
	dec	hl
	ld	c,(hl)
	ld	(hl),e		; get line -2, set line -1
	dec	hl
	ld	(hl),d
	dec	hl
	ld	(hl),e		; set line -1
	dec	hl
	ld	d,(hl)
	ld	(hl),b
	dec	hl
	ld	e,(hl)
	ld	(hl),c		; get line -4, set line -2
	dec	hl
	ld	(hl),b
	dec	hl
	ld	(hl),c		; set line -2
	dec	hl
	ld	b,(hl)
	ld	(hl),d
	dec	hl
	ld	c,(hl)
	ld	(hl),e		; get line -6, set line -4
	dec	hl
	ld	(hl),d
	dec	hl
	ld	(hl),e		; set line -4
	dec	hl
	ld	(hl),b
	dec	hl
	ld	(hl),c		; set line -6
	ld	de,#white_line
	dec	hl
	ld	(hl),d
	dec	hl
	ld	(hl),e		; set white border

	ld	de,#BAR_WIDTH/2*BYTES_PER_WORD
	add	hl,de

	ld	c,(hl)
	inc	hl
	ld	b,(hl)		; get line line 0
	inc	hl
	ld	e,(hl)
	ld	(hl),c
	inc	hl
	ld	d,(hl)
	ld	(hl),b		; get line +1, set line line 0
	inc	hl
	ld	c,(hl)
	ld	(hl),e
	inc	hl
	ld	b,(hl)
	ld	(hl),d		; get line +2, set line +1
	inc	hl
	ld	(hl),e
	inc	hl
	ld	(hl),d		; set line +1
	inc	hl
	ld	e,(hl)
	ld	(hl),c
	inc	hl
	ld	d,(hl)
	ld	(hl),b		; get line +4, set line +2
	inc	hl
	ld	(hl),c
	inc	hl
	ld	(hl),b		; set line +2
	inc	hl
	ld	c,(hl)
	ld	(hl),e
	inc	hl
	ld	b,(hl)
	ld	(hl),d		; get line +6, set line +4
	inc	hl
	ld	(hl),e
	inc	hl
	ld	(hl),d		; set line +4
	inc	hl
	ld	(hl),c
	inc	hl
	ld	(hl),b		; set line +6
	ld	de,#black_line
	inc	hl
	ld	(hl),e
	inc	hl
	ld	(hl),d		; set black border

	exx
	dec	b
	jp	nz,p_bar_loop

	ret

;= Data =========================================================

; Two pictures because of the grey pixels:
picture:
	.include	"magn_bg.inc"
PAC_PIC_SIZE	=	.-picture
UNP_PIC_SIZE	=	UNPACKED
	.if	UNP_PIC_SIZE-PIC_SIZE
	.error	"Wrong size of picture"
	.endif

scroll_line:
	.include	"magn_sl.inc"
PAC_SL_SIZE	=	.-scroll_line
UNP_SL_SIZE	=	UNPACKED

;= Variables ====================================================

	.area	SCRATCH	(ovr)

hrg_file_1:
	.dw	0
hrg_file_2:
	.dw	0

bar_offsets:
	.ds	NUMBER_OF_BARS

white_line:
	.ds	HRG_WIDTH/BITS_PER_BYTE
black_line:
	.ds	HRG_WIDTH/BITS_PER_BYTE

;= Heap usage ===================================================

;		repeated background bitmap
HEAP =		PIC_SIZE*REPETITIONS

;		unpacked background picture
HEAP1 =	HEAP +	PIC_SIZE

;		pointer table for picture 1
HEAP2 =	HEAP +	HRG_HEIGHT*BYTES_PER_WORD
;		pointer table for picture 2
HEAP2 =	HEAP2 +	HRG_HEIGHT*BYTES_PER_WORD
;		pointer table for hrg_file
HEAP2 =	HEAP2 +	HRG_HEIGHT*BYTES_PER_WORD
;		unpacked scroll text
HEAP2 =	HEAP2 +	UNP_SL_SIZE

	.area	HEAP	(abs,ovr)
	.if	HEAP1/HEAP2
	.ds	HEAP1
	.else
	.ds	HEAP2
	.endif

;= The end ======================================================
